package com.heima.article.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.feigns.admin.AdminFeign;
import com.heima.model.admin.pojo.AdChannel;
import com.heima.model.article.pojo.ApArticle;
import com.heima.model.article.vo.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author TheCai
 * @date 2021/6/10 14:35
 **/
@Service
@Slf4j
public class HotArticleServiceImpl implements HotArticleService {
    @Autowired
    ApArticleMapper apArticleMapper;
    /**
     * 计算热文章
     */
    @Override
    public void computeHotArticle() {
        //1.获取近五天的文章数据

        //1.1计算五天前当前的时间   yyyy-MM-dd HH:mm:ss
        String dateStr = LocalDateTime.now().minusDays(5).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toString();

        //1.2查询近五天的文章  publishTime>5天
        List<ApArticle> apArticles = apArticleMapper.loadArticleLists(dateStr);

        // 2.计算文章的分值(封装vo集合)
      List<HotArticleVo> hotArticleVoList = getHotArticleVoList(apArticles);

         //3.按照频道  缓存文章
        cacheToRedisByTag(hotArticleVoList);

    }

    @Autowired
    AdminFeign adminFeign;
    //按照频道  缓存文章
    private void cacheToRedisByTag(List<HotArticleVo> hotArticleVoList) {
        //1.远程查询频道数据
        ResponseResult responseResult = adminFeign.findAll();
        //解析全部频道列表
        List<AdChannel> channelList = JSON.parseArray(JSONUtil.toJsonStr(responseResult.getData()), AdChannel.class);//再用JSON解析一样
        //2.为每个频道 缓存对应频道热点排行前30的文章
                //遍历操作一下
        channelList.forEach(adChannel -> {
            //根据频道id过滤
            List<HotArticleVo> hotArticleByChannel = hotArticleVoList.stream()
                    .filter(articleVo -> articleVo.getChannelId().equals(adChannel.getId()))
                    .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())//reversed降序
                    .limit(30)
                    .collect(Collectors.toList());

            //缓存当前频道文章    cache:缓存
            cacheToRedis(hotArticleByChannel,ArticleConstants.HOT_ARTICLE_FIRST_PAGE+adChannel.getId());

        });

        //3.为推荐频道  缓存所有数据中热度排行前30的文章
                //直接按热度排序收集
        List<HotArticleVo> hotArticleByAll = hotArticleVoList.stream()
                .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())//reversed降序
                .limit(30)
                .collect(Collectors.toList());
        cacheToRedis(hotArticleByAll,ArticleConstants.HOT_ARTICLE_FIRST_PAGE+ArticleConstants.DEFAULT_TAG);

    }
    @Autowired
    RedisTemplate<String,String> redisTemplate;
    //缓存文章集合到redis
    private void cacheToRedis(List<HotArticleVo> hotArticleByChannel, String cacheKey) {
        //把这个hot文章格式变成json的存入redis
        redisTemplate.opsForValue().set(cacheKey,JSONUtil.toJsonStr(hotArticleByChannel));

    }

    /**
     * 计算得分,封装VO
     * @param apArticles
     * @return
     */
    private List<HotArticleVo> getHotArticleVoList(List<ApArticle> apArticles) {
        List<HotArticleVo> hotArticleVos = apArticles.stream().map(apArticle -> {
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle, hotArticleVo);
            //计算得分
            Integer score = computeScre(apArticle);
            //得到热度分值
            hotArticleVo.setScore(score);

            return hotArticleVo;
        }).collect(Collectors.toList());

        return hotArticleVos;
    }
    //计算得分
    private Integer computeScre(ApArticle apArticle) {
        Integer score = 0;
        if (apArticle.getViews()!=null){
            score+=apArticle.getViews()* ArticleConstants.HOT_ARTICLE_VIEW_WEIGHT;
        }
        if (apArticle.getLikes()!=null){
            score+=apArticle.getLikes()*ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if (apArticle.getComment()!=null){
            score+=apArticle.getComment()*ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if (apArticle.getCollection()!=null){
            score+=apArticle.getCollection()*ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }
}
